using System;
using System.Collections.Generic;
using System.Text;

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

namespace ScytheEngine
{
	public class Camera
	{
		#region Data Members 

		private Vector3 m_Position;
		private Quaternion m_Rotation;

		private Matrix m_World;
		private Matrix m_View;
		private Matrix m_Projection;
		private Viewport m_Viewport;

		const float MinDepth = 1.0f;
		const float MaxDepth = 1000.0f;

		#endregion

		#region Ctors
		public Camera(Viewport viewport)
		{
			m_Position = new Vector3( 0, 0, 1 );
			m_Rotation = new Quaternion( 0, 0, 0, 1 );

			SetViewport( viewport );
		}
		#endregion

		#region Methods

		public void SetViewport(Viewport viewport)
		{
			m_Viewport = viewport;

			m_Viewport.MinDepth = MinDepth;
			m_Viewport.MaxDepth = MaxDepth;
		}

		public void Update()
		{
			m_World = Matrix.Identity;

			Matrix viewRotation = Matrix.CreateFromQuaternion( m_Rotation );
			Matrix viewTranslation = Matrix.CreateTranslation( m_Position );

			m_View = Matrix.Invert(viewRotation * viewTranslation );

			m_Projection = Matrix.CreatePerspectiveFieldOfView(
                MathHelper.Pi / 3.0f,
				(float)m_Viewport.Width / (float)m_Viewport.Height,
				m_Viewport.MinDepth,
                m_Viewport.MaxDepth );
		}

        public void Rotate(Vector3 axis, float angle)
        {
            axis = Vector3.Transform(axis, Matrix.CreateFromQuaternion(m_Rotation));
            m_Rotation = Quaternion.Normalize(Quaternion.CreateFromAxisAngle(axis, angle) * m_Rotation);

            Update();
        }

        public void Translate(Vector3 distance)
        {
            m_Position += Vector3.Transform(distance, Matrix.CreateFromQuaternion(m_Rotation));

            Update();
        }

        public void Revolve(Vector3 target, Vector3 axis, float angle)
        {
            Rotate(axis, angle);

            axis = Vector3.Transform(axis, Matrix.CreateFromQuaternion(m_Rotation));
            Quaternion rotate = Quaternion.CreateFromAxisAngle(axis, angle);
            m_Position = Vector3.Transform(target - m_Position, Matrix.CreateFromQuaternion(rotate));

            Update();
        }

		#endregion

		#region Properties

		public Matrix World
		{
			get { return m_World; }
		}

		public Matrix View
		{
			get { return m_View; }
		}

		public Matrix Projection
		{
			get { return m_Projection; }
		}

		public Viewport Viewport
		{
			get { return m_Viewport; }
		}

		#endregion
	}
}
